/*
 * Logger.cpp
 *
 *  Created on: 26/04/2014
 *      Author: ltessore
 */

#include "Logger.h"
#include <iostream>
#include <exception>
#include <ctime>

const unsigned MAX_PID = 10; // Define el maximo tamaño de PID (TODO chequear valor)
const unsigned MAX_NAME = 8; // Define el maximo tamaño de nombre de proceso

/** Namespace con funciones auxiliares */
namespace{
    /** Devuelve la hora local en cadena de tamaño fijo. Ej : Sun Apr 27 15:19:37 2014 */
    std::string get_local_time()
    {
    	time_t rawtime;
    	struct tm * timeinfo;
    	time (&rawtime);
        timeinfo = localtime (&rawtime);
    	std::string time_format(asctime(timeinfo));
    	time_format.resize(24); // Quita el '\n'
    	return time_format;
    }
    /** Devuelve la cantidad de blancos para llenar segun el campo */
    std::string get_blanks(int total, std::string field)
    {
    	int amount_blanks = total - field.size();
    	int i = 0;
    	std::string blanks;
    	while(i < amount_blanks)
    	{
    		blanks+=" ";
    		++i;
    	}
    	return blanks;
    }
}

Logger::Logger(const char* file_name, const char* name_process, pid_t pid_process, bool activate)
    : pid_process_(pid_process),
      activate_(activate)
{
   this->file_name_ = new char[strlen(file_name)];
   strcpy(this->file_name_,file_name);

   this->name_process_ = new char[strlen(name_process)];
   strcpy(this->name_process_, name_process);
   this->fl_.l_type = F_WRLCK ;
   this->fl_.l_whence = SEEK_SET ;
   this->fl_.l_start = 0;
   this->fl_.l_len = 0;
   this->fl_.l_pid = getpid () ;
   this->fd_ = open ( this->file_name_ , O_CREAT | O_WRONLY ,0777 ) ;
   if (fd_ == 0)
   {
	   //No se pudo abrir archivo (NOTE: Atrapar desde afuera)
	   throw std::exception();
   }
}
const char* Logger::get_mode_text(LOG_MODE::Log_Values mode)
{
	switch(mode){
	case LOG_MODE::ERROR:
		return "ERROR";
		break;
	case LOG_MODE::WARN:
		return "WARN ";
		break;
	case LOG_MODE::INFO:
		return "INFO ";
		break;
	default:
		return "";
		break;
	}
}

const char* Logger::convert_text(LOG_MODE::Log_Values  mode,const char * text)
{
    std::string time_format = get_local_time();
	std::stringstream ss;
	std::string line_log = time_format + " [" + this->get_mode_text(mode)+"] " + get_blanks(MAX_PID,ss.str()) +
			               ss.str()+ " ["+ this->name_process_+ "]" + get_blanks(MAX_NAME,this->name_process_)
			               + text + "\n";
	return line_log.c_str();
}

int Logger::write_text(LOG_MODE::Log_Values  mode,const char* text)
{
	if (this->activate_)
	{
	    const char * buffer = this->convert_text(mode,text);
	    if (this->take_lock() != -1)
	    {
		    lseek ( this->fd_ ,0 , SEEK_END ) ;
		    return write ( this->fd_ , buffer , strlen(buffer) ) ;
	    }
	}
	return -1; // No se pudo escribir o NO esta activado el logger
}

int Logger::info(const char* text)
{
	return this->write_text(LOG_MODE::INFO, text);
}

int Logger::warn(const char* text)
{
	return this->write_text(LOG_MODE::WARN, text);
}

int Logger::error(const char* text)
{
	return this->write_text(LOG_MODE::ERROR, text);
}

Logger::~Logger() {
	close ( this->fd_ );

}

int Logger::take_lock()
{
	this->fl_.l_type = F_WRLCK ;
	return fcntl ( this->fd_ , F_SETLKW ,&( this->fl_ ) ) ;
}
int Logger::leave_lock()
{
	this->fl_.l_type= F_UNLCK ;
	return fcntl ( this->fd_ , F_SETLK ,&( this->fl_));

}

